package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.article.feign.AdminFeign;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.HotArticlesService;
import com.heima.common.constans.article.ArticleConstans;
import com.heima.model.admin.pojos.AdChannel;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.vo.HotArticleVo;
import com.heima.model.common.dtos.ResponseResult;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
@Slf4j
public class HotArticlesServiceImpl implements HotArticlesService {
    @Autowired
    ApArticleMapper apArticleMapper;

    @Override
    public void computeHotArticle() {
        //查询前五天文章数据
        String dayParam = DateTime.now().minusDays(5).toString("yyyy-MM-dd hh:mm:dd");
        List<ApArticle> apArticles = apArticleMapper.loadArticleForhot(dayParam);
        //计算文章分值
        List<HotArticleVo> hotArticleVoList = computeHotArticles(apArticles);
        //为每一个频道缓存热点较高的30条文章数据
        cacheToRedisByTag(hotArticleVoList);
    }

    @Autowired
    AdminFeign adminFeign;

    private void cacheToRedisByTag(List<HotArticleVo> hotArticleVoList) {
        if (hotArticleVoList == null || hotArticleVoList.isEmpty()) {
            log.error("计算热点文章列表失败，热点文章列标题为空");
            return;
        }
        //查询所有频道信息
        ResponseResult responseResult = adminFeign.selectAllChannel();
        List<AdChannel> channelList = JSON.parseArray(JSON.toJSONString(responseResult.getData()), AdChannel.class);
        //检索出频道对应的文章列表，并缓存最热门30条到redis中
        for (AdChannel adChannel : channelList) {
            List<HotArticleVo> listByTag = hotArticleVoList.stream()
                    .filter((articleVo) -> articleVo.getChannelId()
                            .equals(adChannel.getId())).collect(Collectors.toList());
            //为每个频道的文章数据 缓存分值最高的30条redis中
            sortAndCache(listByTag, ArticleConstans.HOT_ARTICLE_FIRST_PAGE + adChannel.getId());
        }
    }

    /**
     * 按分值降序排序
     * 缓存前30条到redis
     * cachekey作为key
     *
     * @param listByTag
     * @param cachekey
     */
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    private void sortAndCache(List<HotArticleVo> listByTag, String cachekey) {
        //给推荐频道缓存30条数据 所有文章排序之后的前30
        List<HotArticleVo> hotList = listByTag.stream().sorted(Comparator.comparing(HotArticleVo::getScore).reversed())
                .limit(30)
                .collect(Collectors.toList());
        //保存到缓存中
        stringRedisTemplate.opsForValue().set(cachekey, JSON.toJSONString(hotList));
    }

    /**
     * 计算每篇文章热度值
     *
     * @param apArticles
     * @return
     */
    private List<HotArticleVo> computeHotArticles(List<ApArticle> apArticles) {
        List<HotArticleVo> resultList = new ArrayList<>();
        HotArticleVo hotArticleVo = null;
        //循环遍历每一篇文章
        for (ApArticle apArticle : apArticles) {
            hotArticleVo = new HotArticleVo();
            BeanUtils.copyProperties(apArticle, hotArticleVo);
            //为每一篇文章计算得分
            Integer score = computeScore(apArticle);
            hotArticleVo.setScore(score);
            resultList.add(hotArticleVo);
        }
        //返回积分后的结果
        return resultList;
    }

    /**
     * 计算某一个文章的分值
     *
     * @param apArticle
     * @return
     */
    private Integer computeScore(ApArticle apArticle) {
        Integer score = 0;
        //统计赞得分
        if (apArticle.getLikes() != null) {
            score += apArticle.getLikes() * ArticleConstans.HOT_ARTICLE_LIKE_WEIGHT;
        }
        //统计阅读得分
        if (apArticle.getViews() != null) {
            score += apArticle.getViews();
        }
        //统计评论得分
        if (apArticle.getComment() != null) {
            score += apArticle.getComment() * ArticleConstans.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        //统计收藏得分
        if (apArticle.getCollection() != null) {
            score += apArticle.getCollection() * ArticleConstans.HOT_ARTICLE_COLLECTION_WEIGHT;
        }
        return score;
    }

}
